#include "Buffer.h"

struct Buffer *bufferInit(int size)
{
    struct Buffer *buffer = (struct Buffer *)malloc(sizeof(struct Buffer));
    if (buffer != NULL)
    {
        buffer->data = (char *)malloc(size);
        buffer->cacpacity = size;
        buffer->writepos = buffer->readpos = 0;
        memset(buffer->data, 0, size);
    }
    return buffer;
}

// 需要销毁什么内存，就当作参数传进来
void bufferDestory(struct Buffer *buffer)
{
    if (buffer != NULL)
    {
        if (buffer->data != NULL)
        {
            free(buffer->data);
        }
    }
    free(buffer);
}

// 第二个参数表示你要写入数据的大小
void bufferExtendRoom(struct Buffer *buffer, int size)
{
    // 1. 内存够用 - 不需要扩容
    if (getWriteableCapacity(buffer) >= size)
    {
        return;
    }
    // 2. 内存需要合并才够用 - 不需要扩容
    // 剩余的可写的内存 + 已读的内存 > size
    else if (buffer->readpos + getWriteableCapacity(buffer) >= size)
    {
        // 得到未读的内存大小
        int readable = getReadableCapacity(buffer);
        // 移动内存
        memcpy(buffer->data, buffer->data + buffer->readpos, readable);
        // 更新位置
        buffer->readpos = 0;
        buffer->writepos = readable;
    }
    // 3. 内存不够用 - 扩容
    else
    {
        void *temp = realloc(buffer->data, buffer->cacpacity + size);
        if (temp == NULL)
        {
            return; // 失败了
        }
        memset(temp + buffer->cacpacity, 0, size);
        // 更新数据
        buffer->data = temp;
        buffer->cacpacity += size;
    }
}

int getWriteableCapacity(struct Buffer *buffer)
{

    return buffer->cacpacity - buffer->writepos;
}

int getReadableCapacity(struct Buffer *buffer)
{
    if (buffer->writepos < buffer->readpos)
    {
        printf("Error: writepos is less than readpos\n");
        return 0;
    }
    return buffer->writepos - buffer->readpos;
}

int bufferAppendData(struct Buffer *buffer, const char *data, int size)
{
    // 1 先判断空间够用吗
    if (buffer == NULL || data == NULL || size <= 0)
    {
        return -1;
    }
    // 不一定是做了扩容的操作的
    bufferExtendRoom(buffer, size);

    memcpy(buffer->data + buffer->writepos, data, size);

    buffer->writepos += size;

    return 0;
}

// 直接加长度
int bufferAppendString(struct Buffer *buffer, const char *data)
{
    int size = strlen(data);
    int ret = bufferAppendData(buffer, data, size);
    return ret;
}

int bufferSocketRead(struct Buffer *buffer, int fd)
{
    // read recv readv
    // readv是可以指定多个数组
    struct iovec vec[2];

    // 初始化数组元素
    int writeable = getWriteableCapacity(buffer);
    vec[0].iov_base = buffer->data + buffer->writepos;
    vec[0].iov_len = writeable;
    char *tmp = (char *)malloc(sizeof(char) * 40960);
    // vec[0].iov_base = tmp;
    vec[1].iov_base = tmp;
    vec[1].iov_len = 40960;

    // 返回值是返回的字节数
    int result = readv(fd, vec, 2);
    if (result == -1)
    {
        return -1;
    }
    else if (result <= writeable)
    {
        // 全部写在vec[0]
        buffer->writepos += result;
    }
    else
    {
        buffer->writepos = buffer->cacpacity;
        bufferAppendData(buffer, tmp, result - writeable);
    }
    free(tmp);
    return result;
}

char *bufferFindCRLF(struct Buffer *buffer)
{
    if (!buffer || !buffer->data)
    {
        printf("buffer or buffer->data is NULL\n");
        return NULL;
    }

    size_t readableCapacity = getReadableCapacity(buffer);
    char *start = buffer->data + buffer->readpos;
    printf("Buffer start address: %p\n", (void *)buffer->data);
    printf("Start address: %p, Readable capacity: %zu\n", (void *)start, readableCapacity);

    // 打印缓冲区内容以便检查
    printf("Buffer content: ");
    for (size_t i = 0; i < readableCapacity; i++)
    {
        printf("%c", start[i]);
    }
    printf("\n");

    return memmem(start, readableCapacity, "\r\n", 2);
}

int bufferSendData(struct Buffer *buffer, int socket)
{
    // 判断有无数据 ,判断有多少没有读的数据
    int readable = getReadableCapacity(buffer);

    if (readable > 0)
    {
        // 管道破裂
        // 连接不正常
        int count = send(socket, buffer->data + buffer->readpos, readable, MSG_NOSIGNAL);
        if (count > 0)
        {
            // 把readpos的位置往后移
            buffer->readpos += count;
            usleep(1);
        }
        return count;
    }
    return 0;
}
